package logic

import (
	"core/card"
	"core/command"
	"core/common"
	"core/component/function"
	"core/component/logger"
	"core/component/router"
	"core/component/timer"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"time"
)

type RoomSrv struct {
	rooms            sync.Map //map[uint64]*Room
	roomId           uint64
	Router           *router.Router
	innerRouter      *router.Router
	roomChanMsg      chan *common.PlayerMsgData
	roomInnerMsg     chan []byte
	removeRoomChan   chan []uint64
	timer            *timer.Timer //
	robotOutCardChan chan *common.RobotChanMsg
	stop             chan int
	addRoomChan      chan []*Player
}

func newRoomSrv(processId int) *RoomSrv {
	rSrv := &RoomSrv{
		Router:           router.NewRouter(),
		roomChanMsg:      make(chan *common.PlayerMsgData, 16*4096),
		roomInnerMsg:     make(chan []byte, 16*4096),
		innerRouter:      router.NewRouter(),
		timer:            timer.NewTimer(),
		removeRoomChan:   make(chan []uint64, 16*1024),
		robotOutCardChan: make(chan *common.RobotChanMsg, 16*4096),
		stop:             make(chan int, 1),
		addRoomChan:      make(chan []*Player, 16*4096),
		roomId:           10000000 * uint64(processId), //初始10000起步
	}
	rSrv.registerRoomSrvTimer()
	rSrv.registerRoomSrvHandler()
	go rSrv.loop()
	return rSrv
}

func (rs *RoomSrv) loop() {
	ticker := time.NewTicker(500 * time.Millisecond)
	defer func() {
		if err := recover(); err != nil {
			function.WritePanic(string(debug.Stack()), err)
			return
		}
	}()
	for {
		select {
		case <-ticker.C:
			rs.timer.Loop()
		case msg := <-rs.roomChanMsg:
			rs.doRoomChanMsg(msg)
		case rms := <-rs.removeRoomChan:
			for _, roomID := range rms {
				rs.removeRoom(roomID)
			}
		case msg := <-rs.robotOutCardChan:
			rs.doRobotChanMsg(msg)
		case players := <-rs.addRoomChan:
			rs.addRoom(players)
		case <-rs.stop:
			ticker.Stop()
			return
		}
	}
}

func (rs *RoomSrv) doRobotChanMsg(msg *common.RobotChanMsg) {
	rm, ok := rs.rooms.Load(msg.RoomId)
	if !ok {
		return
	}
	rm.(*Room).robotOutOfCards(msg.Info.(*RoomPlayer))
}

func (rs *RoomSrv) sendCreateRoomWithPlayers(players []*Player) {
	select {
	case rs.addRoomChan <- players:
	default:
		logger.Error("[消息]转发消错误")
		return
	}
}

func (rs *RoomSrv) sendRobotChanMsg(msg *common.RobotChanMsg) {
	select {
	case rs.robotOutCardChan <- msg:
	default:
		logger.Error("[消息]转发消错误")
		return
	}
}

func (rs *RoomSrv) sendRemoveRoom(rms ...uint64) {
	rs.removeRoomChan <- rms
}

func (rs *RoomSrv) checkOutOfCardTimeOut() {
	rs.rooms.Range(func(key, value interface{}) bool {
		room, ok := value.(*Room)
		if ok {
			room.checkOutOfCardTimeOut()
		}
		return true
	})
}

func (rs *RoomSrv) judgeRoomRealPlayerNum() {
	rms := make([]uint64, 0)
	rs.rooms.Range(func(key, value interface{}) bool {
		room, ok := value.(*Room)
		if !ok {
			return true
		}
		num := 0
		room.players.Range(func(key, value any) bool {
			p, ok := value.(*RoomPlayer)
			if !ok {
				return true
			}
			if !p.robot() {
				num++
			}
			return true
		})
		if num == 0 {
			rms = append(rms, room.roomId)
		}
		return true
	})
	if len(rms) != 0 {
		rs.sendRemoveRoom(rms...)
	}
}

func (rs *RoomSrv) doRoomChanMsg(msg *common.PlayerMsgData) {
	_, err := world.roomSrv.Router.RouterRoomSrvMsg(msg.Data)
	if err == nil {
		logger.Info("消息路由到roomSrv")
		return
	}
	WorldGetMe().playerChanMsg <- msg
}

func (rs *RoomSrv) sendMsgToRoomSrv(msg *common.PlayerMsgData) {
	rs.roomChanMsg <- msg
}

//func (rs *RoomSrv) sendRoomInnerMsg() {
//
//}

func (rs *RoomSrv) removeRoom(roomId uint64) {
	val, ok := rs.rooms.Load(roomId)
	if !ok {
		return
	}
	rm, ok := val.(*Room)
	if !ok {
		return
	}
	rs.rooms.Delete(rm.roomId)
	rm.cardGroupManager = nil
	rm.clearRoomPlayer()
	rm.players = nil
	rm = nil
	logger.Infof("移除房间成功 roomID:%v", roomId)
}

func (rs *RoomSrv) getRoom(roomId uint64) *Room {
	rm, ok := rs.rooms.Load(roomId)
	if !ok {
		return nil
	}
	return rm.(*Room)
}

func (rs *RoomSrv) addRoom(players []*Player) {
	atomic.AddUint64(&rs.roomId, 1)
	rs.rooms.Store(rs.roomId, newRoom(rs.roomId, players, rs))
	logger.Infof("[匹配成功，进入房间] roomId=%v players=%v", rs.roomId, players)
}

func (rs *RoomSrv) outOfCard(roomId uint64, cards []string, playerId uint64) {
	var (
		result   bool
		cardType command.CardType
	)
	room := rs.getRoom(roomId)
	if room == nil {
		return
	}
	defer func() {
		if !result {
			msgSend := &command.SCOutOfCardsPvp{
				PlayerId: playerId,
				Ret:      result,
				CardType: cardType,
			}
			room.sendRoomOnePlayerMsg(command.Command_SCOutOfCardsInfo_Pvp, msgSend, playerId)
		}
	}()
	if len(cards) != 0 {
		cardTypeStr, _ := card.CardsMgrGetMe().PokersValue(card.CardsMgrGetMe().ToPokers(card.CardsMgrGetMe().CardTurnOff(cards)))
		cardType = card.CardsMgrGetMe().GetCardTypeByC(cardTypeStr)
		if cardType == command.CardType_error_type {
			return
		}
	}
	roomPlayer := room.getRoomPlayer(playerId)
	if roomPlayer == nil {
		return
	}
	if !roomPlayer.checkCardInHand(cards) {
		return
	}
	ok := room.judgeOutCardSuccess(playerId, cards)
	if !ok {
		return
	}
	room.outOfCards(cards, roomPlayer, cardType)
	result = true

	logger.Infof("[玩家出牌] result=%v roomId=%v playerId=%v outCards=%v cardType=%v surplusCards=%v",
		true, room.roomId, playerId, cards, cardType, roomPlayer.cards)
}

func (rs *RoomSrv) chatMsg(roomId, playerId uint64, msg string) {
	rm := rs.getRoom(roomId)
	if rm == nil {
		return
	}
	rp := rm.getRoomPlayer(playerId)
	if rp == nil {
		return
	}
	msgSend := &command.SCChatMsg{
		PlayerId: playerId,
		Msg:      msg,
		Name:     rp.owner.nickName,
	}
	rm.sendRoomMsg(command.Command_SCChatMsg_Online, msgSend)
}

func (rs *RoomSrv) playerLeave(roomId uint64, playerId uint64) {
	rm, ok := rs.rooms.Load(roomId)
	if !ok {
		return
	}
	rm.(*Room).playerLeave(playerId)
}
